package se.webbzon.boltzmann.game.object.inventory;

import java.awt.Dimension;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.List;

import se.webbzon.boltzmann.game.object.inventory.layout.AbstractGameInventoryLayout;
import se.webbzon.boltzmann.game.object.inventory.layout.ArrowLayout;
import se.webbzon.boltzmann.game.object.inventory.page.AbstractGameInventoryPage;
import se.webbzon.boltzmann.game.object.inventory.page.ItemInventoryPage;
import se.webbzon.boltzmann.game.object.inventory.page.MinigameInventoryPage;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.hud.HudCursor;
import se.webbzon.boltzmann.hud.TopBar;
import se.webbzon.boltzmann.input.Input;
import se.webbzon.boltzmann.input.Button;
import se.webbzon.boltzmann.input.InputListener;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;
import se.webbzon.oschi01.worldobject.WorldObject;

public class GameInventory extends WorldObject {
	
	// The 2-dimensional depth of the inventory
	private static final int depth = -1;
	
	// The player associated with this inventory
	private final AbstractPlayerCharacter player;
	
	// The input listener used for this inventory;
	private final InputListener inputListener;
	
	// The visibility of the inventory
	private volatile boolean visible;
	
	// The layout of the arrows in the inventory
	private final ArrowLayout arrowLayout;
	private final Dimension leftArrowSize, rightArrowSize;
	
	// The current page in the inventory and its index
	private volatile AbstractGameInventoryPage currentPage;
	private volatile int currentPageIndex = 0; 
	
	// A list of all the pages in the inventory
	private final List<AbstractGameInventoryPage> pages;
	
	// The cursor of the inventory
	private final HudCursor cursor;
	
	// The top bar of the inventory
	private final TopBar topBar;
	
	// Whatever the left or right arrow are selected
	private volatile boolean leftArrowSelected, rightArrowSelected;
	
	// The player blocker
	private volatile Object playerBlocker;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a a new game inventory. **/
	public GameInventory(AbstractPlayerCharacter player, AbstractGameInventoryLayout layout) {
		super(	WorldObject.onCreate + WorldObject.onDestroy + 
				WorldObject.onStep + WorldObject.onPostDraw,
				depth);
		
		this.player = player;
		inputListener = new InputListenerImpl();
		
		arrowLayout = layout.getArrowLayout();
		final ImageObserver o = player.getPlayer().getImageObserver();
		int arrowWidth, arrowHeight;
		arrowWidth = arrowLayout.getLeftArrowImage().get(0).getWidth(o);
		arrowHeight = arrowLayout.getLeftArrowImage().get(0).getHeight(o);
		leftArrowSize = new Dimension(arrowWidth,arrowHeight);
		arrowWidth = arrowLayout.getRightArrowImage().get(0).getWidth(o);
		arrowHeight = arrowLayout.getRightArrowImage().get(0).getHeight(o);
		rightArrowSize = new Dimension(arrowWidth,arrowHeight);
		
		topBar = new TopBar(player.getPlayer(),layout.getTopBarLayout());
		cursor = new HudCursor(layout.getCursorLayout());
		
		pages = new ArrayList<AbstractGameInventoryPage>();
		pages.add(new ItemInventoryPage(this,player.getPlayer(),layout.getItemLayout()));
		pages.add(new MinigameInventoryPage(this,player.getPlayer(),layout.getMinigameLayout()));
		
		currentPageIndex = 0;
		currentPage = pages.get(0);
		
		visible = false;
		
		selectLeftArrow();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the cursor associated with this game inventory. **/
	public HudCursor getCursor() {
		return cursor;
	}
	
	/** Moves the cursor to the left arrow. **/
	public void selectLeftArrow() {
		leftArrowSelected = true;
		rightArrowSelected = false;
		cursor.setPosition(	arrowLayout.getLeftArrowXOffset() + 
							leftArrowSize.width/2,
							arrowLayout.getLeftArrowYOffset() + 
							leftArrowSize.height/2);
	}
	
	/** Moves the cursor to the right arrow. **/
	public void selectRightArrow() {
		leftArrowSelected = false;
		rightArrowSelected = true;
		cursor.setPosition(	arrowLayout.getRightArrowXOffset() + 
							rightArrowSize.width/2,
							arrowLayout.getRightArrowYOffset() + 
							rightArrowSize.height/2);
	}
	
	@Override public void onCreate(WorldArea world) {
		world.createInstance(cursor);
		world.createInstance(topBar);
		player.getPlayer().getInput().addListener(inputListener);
	}
	
	@Override public void onDestroy(WorldArea world) {
		player.getPlayer().getInput().removeListener(inputListener);
		world.destroyInstance(cursor);
		world.destroyInstance(topBar);
	}
	
	
	
	@Override public void onPostDraw(WorldArea world, WorldCameraPane hud) {
		if (!visible)
			return;
		
		int image;
		image = leftArrowSelected ? 0:1;
		hud.drawImage(	arrowLayout.getLeftArrowImage().get(image), 
						arrowLayout.getLeftArrowXOffset(), 
						arrowLayout.getLeftArrowYOffset());
		image = rightArrowSelected ? 0:1;
		hud.drawImage(	arrowLayout.getRightArrowImage().get(image),
						arrowLayout.getRightArrowXOffset(), 
						arrowLayout.getRightArrowYOffset());
		
		currentPage.onDraw(hud);
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Shows the next page in the game inventory. **/
	private void nextPage() {
		if (currentPageIndex == pages.size()-1)
			currentPageIndex = 0;
		else
			currentPageIndex++;
		currentPage = pages.get(currentPageIndex);
	}
	
	/** Shows the previous page in the game inventory. **/
	private void previousPage() {
		if (currentPageIndex == 0)
			currentPageIndex = pages.size()-1;
		else
			currentPageIndex--;
		currentPage = pages.get(currentPageIndex);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class InputListenerImpl implements InputListener {

		@Override public void primaryAxisChanged(	Input input, 
													double direction,
													double value) {};

		@Override public void secondaryAxisChanged(	Input input, 
													double direction,
													double value) {};

		@Override public void buttonPressed(Input input, Button button) {
			if (player.getPlayer().getInput() == input) {
				if (button == Button.INVENTORY && (player.isBlocked() == visible)) {
					// Show/Hide inventory
					visible = !visible;
					cursor.setVisible(visible);
					topBar.setForceShow(visible);
					
					if (playerBlocker == null)
						playerBlocker = player.containBlocker();
					else {
						player.releaseBlocker(playerBlocker);
						playerBlocker = null;
					}
				} else if (visible) {
					// Check the key
					switch(button) {
					case ACTION:
						if (rightArrowSelected)
							nextPage();
						else if (leftArrowSelected)
							previousPage();
						else
							currentPage.buttonPressed(button);
						break;
					case LEFT:
						// Move the cursor to the left
						if (rightArrowSelected) {
							currentPage.onEnterRight();
							rightArrowSelected = false;
						} else if (!leftArrowSelected)
							currentPage.buttonPressed(button);
						break;
					case RIGHT:
						// Move the cursor to the right
						if (leftArrowSelected) {
							currentPage.onEnterLeft();
							leftArrowSelected = false;
						} else if (!rightArrowSelected)
							currentPage.buttonPressed(button);
						break;
					default:
						// Send button to page
						if (!leftArrowSelected && !rightArrowSelected)
							currentPage.buttonPressed(button);
						break;
					}

				} else switch (button) {
				// Show top bar
				case NEXT_ITEM:
				case PREVIOUS_ITEM:
				case NEXT_CHARACTER:
				case PREVIOUS_CHARACTER:
					topBar.show();
					break;
				}
			}
		}

		@Override public void buttonReleased(Input input, Button button) {};
		
		@Override public void bindingAccepted(Input input, Button button) {};
		
	}

}
